home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
rpg
/
crossfir.92
/
crossfir
/
crossfire-0.92.5
/
server
/
xio.c
< prev
Wrap
C/C++ Source or Header
|
1996-07-24
|
89KB
|
2,625 lines
/*
* static char *rcsid_xio_c =
* "$Id: xio.c,v 1.44 1996/03/06 06:41:40 master Exp $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 1994 Mark Wedel
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author can be reached via e-mail to master@rahul.net
*/
#ifdef ds
#include <stddef.h>
#endif
#include <bitmaps.h>
#include <global.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
#include <xio.h>
#include <spells.h>
#include <skills.h>
#include <object.h>
#include <stdarg.h>
static char font_text_stats[]="8x13";
static char font_text_info[]="8x13";
static char font_inv_text[]="8x13";
#ifdef USE_BUTTONS
static char *dirnames [NUMDIRBUTTS] = {
"NW","No","NE","We","Br","Ea","SW","So","SE"};
static char *opnames [NUMOPBUTTS] = {
"Change","Apply","Peace ","Talk "};
int dirX [NUMDIRBUTTS] = {186, 216, 246,186,216,246,186,216,246};
int dirY [NUMDIRBUTTS] = {1,1,1,21,21,21,41,41,41};
int dirW = 20;
int opX [NUMOPBUTTS] = {158,218,158,218};
int opY [NUMOPBUTTS] = {61,61,81,81};
#endif
int IOerrors(Display *d) {
player *pl;
char buf[MAX_BUF];
LOG(llevError,"Fatal error on display.\n");
/* Give pass 1 to emergency save - this tells it that it is only a backup
* copy should be made, and that it shouldn't free any data. Since we want
* to try and continue from this error, that is what we want.
*/
emergency_save(1);
if(editor)
exit(-1);
for(pl=first_player;pl!=NULL;pl=pl->next)
if(pl->gdisp==d)
break;
if(pl==NULL)
return 0;
save_player(pl->ob, 1);
LOG(llevError,"Player %s lost the display.\n",pl->name);
(void) sprintf(buf,"%s lost connection.",pl->name);
remove_lock(pl);
/* prevent updating inventory of player for whom there is no longer a
** functional display */
pl->freeze_inv = 1;
if(pl->ob->map!=NULL)
pl->ob->map->players--;
if(pl->ob->state== ST_PLAYING ||pl->ob->state==ST_CHANGE_CLASS ||
pl->ob->state==ST_CONFIGURE)
if( !QUERY_FLAG(pl->ob,FLAG_REMOVED)) remove_ob(pl->ob);
destroy_object(pl->ob);
free_object(pl->ob);
free_player(pl);
/*
* If in a server-mode, I assume a shell-script is restarting it.
* Thus I exit if I can, since some variables can be messed up by the
* longjmp() below.
*
* If we are in server mode, don't exit. This way, maps don't reset.
*/
if(first_player==NULL && server_mode !=SERVER_ENABLED) {
LOG(llevError,"Only 1 player - exiting the program.\n");
exit(0);
}
new_draw_info(NDI_UNIQUE | NDI_ALL, 5, NULL, buf);
#ifdef LONGJUMP
longjmp(jump_addr,1);
#else
fatal_signal(0, 1);
#endif
return 0;
}
int Xerrors(Display *d,XErrorEvent *err) {
char buf[MAX_BUF];
XGetErrorText(d,err->error_code,buf,MAX_BUF);
LOG(llevError,"Error code %s\n",buf);
return 0;
}
void setuperrors() {
XSetIOErrorHandler(IOerrors);
XSetErrorHandler(Xerrors);
}
int get_root_display(player *p, char *display) {
#ifdef HAVE_SAVE_UID
uid_t olduid;
#endif
char *cp;
#if 0
XSetWindowAttributes attr;
#endif
#ifdef HAVE_SAVE_UID
olduid = geteuid(); /* I like to run it suid :) */
setuid(getuid()); /* Have to this to open display, */
/* if anyone is using xauth like me. */
#endif
p->gdisp=XOpenDisplay(display);
if (!p->gdisp) {
sprintf(errmsg, "Can't open display %s.", display);
return 1;
}
if ((cp=XGetDefault(p->gdisp,name,"splitwindow")) != NULL)
if (!strcmp("on",cp) || !strcmp("yes",cp))
p->split_window = 1;
else if (!strcmp("off",cp) || !strcmp("no",cp))
p->split_window = 0;
if ((cp=XGetDefault(p->gdisp,"crossfire","pixmap")) != NULL)
if (!strcmp("on",cp) || !strcmp("yes",cp))
p->use_pixmaps = 1;
else if (!strcmp("off",cp) || !strcmp("no",cp))
p->use_pixmaps = 0;
#ifdef HAVE_SAVE_UID
setuid(olduid); /* Back to owner of suid crossfire */
#else
setuid(geteuid()); /* We want both ruid == euid */
#endif
/*
XAutoRepeatOff(p->gdisp);
*/
p->gscreen=DefaultScreen(p->gdisp);
p->gbackground=WhitePixel(p->gdisp,p->gscreen);
p->gforeground=BlackPixel(p->gdisp,p->gscreen);
p->roothint.x=0,p->roothint.y=0;
p->roothint.width=582+6+INFOCHARS*FONTWIDTH;
p->roothint.height=482;
p->roothint.max_width=p->roothint.min_width=p->roothint.width;
p->roothint.max_height=p->roothint.min_height=p->roothint.height;
p->roothint.flags=PPosition | PSize;
if(!p->split_window) {
p->win_root=XCreateSimpleWindow(p->gdisp,DefaultRootWindow(p->gdisp),
p->roothint.x,p->roothint.y,p->roothint.width,p->roothint.height,2,
p->gbackground,p->gforeground);
p->iscolor=allocate_colors(p->gdisp, p->win_root, p->gscreen,
&p->colormap, p->discolor);
if (p->iscolor){
p->gforeground=p->discolor[0].pixel;
p->gbackground=p->discolor[8].pixel;
/* We need to set this here - while we pretend to set it in the
* XCreateSimpleWindow above, we actually haven't set the colors yet.
*/
XSetWindowBackground(p->gdisp, p->win_root, p->gforeground);
XSetWindowBorder(p->gdisp, p->win_root, p->gbackground);
}
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_root,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_root,name,name,
p->pixmap,gargv,gargc,&(p->roothint));
p->gc_root=XCreateGC(p->gdisp,p->win_root,0,0);
XSetForeground(p->gdisp,p->gc_root,p->gforeground);
XSetBackground(p->gdisp,p->gc_root,p->gbackground);
}
if(!p->use_pixmaps)
p->use_pixmaps = fixfontpath(p->gdisp,p->name);
if(!p->split_window) {
if(!p->use_pixmaps) {
p->font=XLoadFont(p->gdisp,font_graphic);
XSetFont(p->gdisp,p->gc_root,p->font);
}
XSelectInput(p->gdisp,p->win_root,KeyPressMask|
KeyReleaseMask|ExposureMask|StructureNotifyMask);
XMapRaised(p->gdisp,p->win_root);
XNextEvent(p->gdisp,&p->gevent);
}
setuperrors();
return 0;
}
int get_game_display(player *p,char *display) {
char *cp;
p->gamehint.x=305,p->gamehint.y=104;
p->gamehint.width=269,p->gamehint.height=269;
p->gamehint.max_width=p->gamehint.min_width=p->gamehint.width;
p->gamehint.max_height=p->gamehint.min_height=p->gamehint.height;
p->gamehint.flags=PPosition | PSize;
p->win_game=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->gamehint.x,p->gamehint.y,p->gamehint.width,p->gamehint.height,2,
p->gbackground,p->gforeground);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_game,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
if (p->split_window) {
p->iscolor=allocate_colors(p->gdisp, p->win_game, p->gscreen,
&p->colormap, p->discolor);
if (p->iscolor){
p->gforeground=p->discolor[0].pixel;
p->gbackground=p->discolor[8].pixel;
/* We need to set this here - while we pretend to set it in the
* XCreateSimpleWindow above, we actually haven't set the colors yet.
*/
XSetWindowBackground(p->gdisp, p->win_game, p->gforeground);
XSetWindowBorder(p->gdisp, p->win_game, p->gbackground);
}
} else if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_game, p->colormap);
XSetStandardProperties(p->gdisp,p->win_game,"Crossfire",name,
p->pixmap,gargv,gargc, &(p->gamehint));
/* Eneq(@csd.uu.se): Has to load the chrfont from the resources here. */
if((cp=XGetDefault(p->gdisp,name,"chrfont"))!=NULL||chrfont!=NULL) {
XFontStruct *tmp;
if (chrfont!=NULL)
cp=chrfont;
if ((tmp=XLoadQueryFont(p->gdisp, cp)) != NULL) {
strcpy (p->font_str, cp);
XFreeFont(p->gdisp, tmp);
} else
LOG(llevError, "Crossfire: Couldn't load font %s.\n", cp);
}
p->gc_game=XCreateGC(p->gdisp,p->win_game,0,0);
if (p->iscolor){
XSetForeground(p->gdisp,p->gc_game,p->discolor[0].pixel);
XSetBackground(p->gdisp,p->gc_game,p->discolor[12].pixel);
}
else{
XSetForeground(p->gdisp,p->gc_game,p->gforeground);
XSetBackground(p->gdisp,p->gc_game,p->gbackground);
}
XSetGraphicsExposures(p->gdisp, p->gc_game, False);
if(!p->use_pixmaps) {
p->game_font=p->font=XLoadFont(p->gdisp,font_graphic);
XSetFont(p->gdisp,p->gc_game,p->font);
}
if (p->color_pixmaps) {
p->gc_xpm_floor = XCreateGC(p->gdisp,p->win_game,0,0);
p->gc_xpm_object = XCreateGC(p->gdisp,p->win_game,0,0);
XSetGraphicsExposures(p->gdisp, p->gc_xpm_floor, False);
XSetGraphicsExposures(p->gdisp, p->gc_xpm_object, False);
XSetClipOrigin(p->gdisp, p->gc_xpm_object,
0, 0);
p->xpm_pixmap = XCreatePixmap(p->gdisp, RootWindow(p->gdisp,
DefaultScreen(p->gdisp)), 24, 24, DefaultDepth(p->gdisp,
DefaultScreen(p->gdisp)));
}
XSelectInput(p->gdisp,p->win_game,
ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
XMapRaised(p->gdisp,p->win_game);
return 0;
}
int get_info_display(player *p,char *name) {
p->infohint.x=579,p->infohint.y=0;
p->infohint.width=6+INFOCHARS*FONTWIDTH,p->infohint.height=11+p->infolines*13;
p->infohint.min_width=100;
p->infohint.min_height=30;
p->infohint.flags=PPosition | PSize;
p->win_info=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->infohint.x,p->infohint.y,p->infohint.width,p->infohint.height,2,
p->gforeground,p->gbackground);
if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_info, p->colormap);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_info,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_info,"Crossfire - text","Crosstext",
p->pixmap,gargv,gargc,&(p->infohint));
p->gc_info=XCreateGC(p->gdisp,p->win_info,0,0);
XSetForeground(p->gdisp,p->gc_info,p->gforeground);
XSetBackground(p->gdisp,p->gc_info,p->gbackground);
p->font=XLoadFont(p->gdisp,font_text_info);
XSetFont(p->gdisp,p->gc_info,p->font);
XSelectInput(p->gdisp,p->win_info,
ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
StructureNotifyMask);
XMapRaised(p->gdisp,p->win_info);
return 0;
}
void resize_win_info(player *p,XEvent *event) {
int chars=(event->xconfigure.width/FONTWIDTH)-1;
int lines=(event->xconfigure.height/FONTHEIGHT);
int i;
char **info;
if(chars==p->infochars&&lines==p->infolines)
return;
if(chars<3||lines<3)
return;
info=(char **) malloc(sizeof(char *) * lines);
/* If the new window is smaller, we want to lose the oldest lines
* in the window. This is not necessarily the same thing as the
* bottom lines of the display.
* If the buffer hasn't filled up yet (infofull==0), then
* the oldes lines are those starting at 0.
* If in wrap mode, the oldest lines are those after infoline. If
* in scroll mode, the oldest are those after infopos.
* I had to re-write this function pretty majorly to do this.
* Mark S. Wedel (master@rahul.net)
*/
if (lines<p->infolines) {
int diff = p->infolines - lines,start;
if (!p->infofull) {
if (p->infoline>lines) start=p->infoline-lines;
else start=0;
}
else if (!p->scroll) start = p->infoline + diff;
else start = p->infopos + diff;
for (i=0; i<lines; i++) {
info[i]= (char *) malloc(sizeof(char) * (chars+1));
strncpy(info[i], p->info[(i+start) % p->infolines],chars);
info[i][chars]='\0';
}
if (p->infoline>=lines) p->infoline = lines-1;
if (p->infopos>=lines) p->infopos = lines-1;
p->infofull = 0;
}
else {
/* If the window is getting bigger, things are a little simpler
* than above. However, for the data in scroll mode to make
* sense, we do need to re-copy it in a make sense way.
* MSW (master@cats.ucsc.edu)
*/
int start;
if (!p->infofull) start=0;
else {
if (p->scroll)
start = p->infopos;
else start = p->infoline;
/* the way we copy the lines makes it so the oldest is
* line 0, and the newest is the last line. so update
* p->infoline accordingly
*/
p->infoline = lines-1;
p->infopos = lines - 1;
}
for (i=0; i<p->infolines; i++) {
info[i]= (char *) malloc(sizeof(char) * (chars+1));
strncpy(info[i], p->info[(i+start) % p->infolines], chars);
info[i][chars]='\0';
}
for (i=p->infolines; i<lines; i++) {
info[i]= (char *) malloc(sizeof(char) * (chars+1));
info[i][0]='\0';
}
p->infofull = 0;
}
for(i=0;i<p->infolines;i++)
free(p->info[i]);
free(p->info);
if(p->writing>=chars)
p->writing=chars-1;
p->info=info;
p->infochars=chars;
p->infolines=lines;
refresh_win_info(p->ob);
}
void resize_win_inv(player *p,XEvent *event) {
int x=event->xconfigure.width;
int y=event->xconfigure.height;
int lines=(y-FONTHEIGHT-8)/24;
if(x==p->invhint.x&&y==p->invhint.y)
return;
if(lines>MAX_INV_SIZE)
lines=MAX_INV_SIZE;
p->inv_size=lines;
if (p->show_inv_icon)
p->inv_chars=(x-88)/FONTWIDTH;
else
p->inv_chars=(x-60)/FONTWIDTH;
p->invhint.width=x;
p->invhint.height=y;
p->barlength_inv=lines*24;
sprintf(p->format_inv,"%%-%d.%ds%%-6s",p->inv_chars-6,p->inv_chars-6);
draw_all_inventory(p->ob);
}
void resize_win_look(player *p,XEvent *event) {
int x=event->xconfigure.width;
int y=event->xconfigure.height;
int lines=(y-FONTHEIGHT-8)/24;
int chars=(x-60)/FONTWIDTH;
if(x==p->lookhint.x&&y==p->lookhint.y)
return;
if(lines>MAX_LOOK_SIZE)
lines=MAX_LOOK_SIZE;
p->look_size=lines;
p->look_chars=chars;
p->lookhint.width=x;
p->lookhint.height=y;
p->barlength_look=lines*24;
sprintf(p->format_look,"%%-%d.%ds%%-6s",chars-6,chars-6);
draw_all_look(p->ob);
}
int get_message_display(player *p,char *name) { /* Misc-window */
p->messagehint.x=303,p->messagehint.y=378;
p->messagehint.width=273,p->messagehint.height=101;
p->messagehint.max_width=p->messagehint.min_width=p->messagehint.width;
p->messagehint.max_height=p->messagehint.min_height=p->messagehint.height;
p->messagehint.flags=PPosition | PSize;
p->win_message=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->messagehint.x,p->messagehint.y,p->messagehint.width,
p->messagehint.height,2,p->gforeground,p->gbackground);
if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_message, p->colormap);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_message,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_message,"Crossfire - vitals",
"crossvitals",p->pixmap,
gargv,gargc,&(p->messagehint));
p->gc_message=XCreateGC(p->gdisp,p->win_message,0,0);
XSetForeground(p->gdisp,p->gc_message,p->gforeground);
XSetBackground(p->gdisp,p->gc_message,p->gbackground);
p->font=XLoadFont(p->gdisp,font_text_info);
XSetFont(p->gdisp,p->gc_message,p->font);
XSelectInput(p->gdisp,p->win_message,
ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
XMapRaised(p->gdisp,p->win_message);
return 0;
}
int get_inv_display(player *p,char *name) {
#ifdef OBWIN
p->inv=create_obwin(p,0,0,300,310,p->split_window,"inventory");
#else
p->invhint.x=0,p->invhint.y=0;
p->invhint.width=300,p->invhint.height=310;
p->invhint.min_width=60+10*FONTWIDTH;
p->invhint.min_height=FONTHEIGHT+8+24*2;
p->invhint.flags=PPosition | PSize;
p->win_inv=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->invhint.x,p->invhint.y,p->invhint.width,p->invhint.height,2,
p->gforeground,p->gbackground);
if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_inv, p->colormap);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_inv,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_inv,"Crossfire - inventory",
"crossinventory",p->pixmap,gargv,gargc,
&(p->invhint));
XSelectInput(p->gdisp,p->win_inv,
ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
StructureNotifyMask);
XMapRaised(p->gdisp,p->win_inv);
p->gc_inv_text=XCreateGC(p->gdisp,p->win_inv,0,0);
p->gc_inv_icon=XCreateGC(p->gdisp,p->win_inv,0,0);
/* Always create these, even thow we may not need them. The space they use
* is probably minimal, and to create/destroy them each time the user
* switches would get pretty messy.
*/
p->gc_inv_status_icon = XCreateGC(p->gdisp,p->win_inv,0,0);
XSetForeground(p->gdisp,p->gc_inv_status_icon,p->gforeground);
XSetBackground(p->gdisp,p->gc_inv_status_icon,p->gbackground);
XSetGraphicsExposures(p->gdisp, p->gc_inv_status_icon, False);
XSetForeground(p->gdisp,p->gc_inv_text,p->gforeground);
XSetBackground(p->gdisp,p->gc_inv_text,p->gbackground);
XSetForeground(p->gdisp,p->gc_inv_icon,p->gforeground);
XSetBackground(p->gdisp,p->gc_inv_icon,p->gbackground);
XSetGraphicsExposures(p->gdisp, p->gc_inv_icon, False);
p->font=XLoadFont(p->gdisp,font_inv_text);
XSetFont(p->gdisp,p->gc_inv_text,p->font);
if(!p->use_pixmaps) {
p->font=XLoadFont(p->gdisp,font_graphic);
XSetFont(p->gdisp,p->gc_inv_status_icon,p->font);
XSetFont(p->gdisp,p->gc_inv_icon,p->font);
}
#endif
return 0;
}
int get_look_display(player *p,char *name) {
p->lookhint.x=0,p->lookhint.y=313;
p->lookhint.width=300,p->lookhint.height=166;
p->lookhint.min_width=60+10*FONTWIDTH;
p->lookhint.min_height=FONTHEIGHT+8+24*2;
p->lookhint.flags=PPosition | PSize;
p->win_look=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->lookhint.x,p->lookhint.y,p->lookhint.width,p->lookhint.height,2,
p->gforeground,p->gbackground);
if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_look, p->colormap);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_look,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_look,"Crossfire - look",
"crosslook",p->pixmap,gargv,gargc,
&(p->lookhint));
p->gc_look_text=XCreateGC(p->gdisp,p->win_look,0,0);
p->gc_look_icon=XCreateGC(p->gdisp,p->win_look,0,0);
XSetForeground(p->gdisp,p->gc_look_text,p->gforeground);
XSetBackground(p->gdisp,p->gc_look_text,p->gbackground);
XSetForeground(p->gdisp,p->gc_look_icon,p->gforeground);
XSetBackground(p->gdisp,p->gc_look_icon,p->gbackground);
XSetGraphicsExposures(p->gdisp, p->gc_look_icon, False);
p->font=XLoadFont(p->gdisp,font_inv_text);
XSetFont(p->gdisp,p->gc_look_text,p->font);
if(!p->use_pixmaps) {
p->font=XLoadFont(p->gdisp,font_graphic);
XSetFont(p->gdisp,p->gc_look_icon,p->font);
}
XSelectInput(p->gdisp,p->win_look,
ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
StructureNotifyMask);
XMapRaised(p->gdisp,p->win_look);
return 0;
}
int get_stats_display(player *p,char *name) {
p->stathint.x=303,p->stathint.y=0;
p->stathint.width=273,p->stathint.height=100;
p->stathint.min_width=p->stathint.max_width=p->stathint.width;
p->stathint.min_height=p->stathint.max_height=p->stathint.height;
p->stathint.flags=PPosition | PSize;
p->win_stats=XCreateSimpleWindow(p->gdisp,
p->split_window?DefaultRootWindow(p->gdisp):p->win_root,
p->stathint.x,p->stathint.y,p->stathint.width,p->stathint.height,2,
p->gforeground,p->gbackground);
if (p->iscolor)
XSetWindowColormap(p->gdisp, p->win_stats, p->colormap);
p->pixmap=XCreateBitmapFromData(p->gdisp,p->win_stats,
(_Xconst char *) crossfire_bits,
(unsigned int) crossfire_width, (unsigned int)crossfire_height);
XSetStandardProperties(p->gdisp,p->win_stats,"Crossfire - status",
"crosstatus",p->pixmap,gargv,gargc,
&(p->stathint));
p->gc_stats=XCreateGC(p->gdisp,p->win_stats,0,0);
XSetForeground(p->gdisp,p->gc_stats,p->gforeground);
XSetBackground(p->gdisp,p->gc_stats,p->gbackground);
p->font=XLoadFont(p->gdisp,font_text_stats);
XSetFont(p->gdisp,p->gc_stats,p->font);
XSelectInput(p->gdisp,p->win_stats,
KeyPressMask|KeyReleaseMask|ExposureMask);
XMapRaised(p->gdisp,p->win_stats);
return 0;
}
#ifdef SET_TITLE
void redraw_title(object *pl)
{
char buf[MAX_BUF];
if (pl->contr->own_title[0]=='\0')
sprintf(buf,"Player: %s the %s",pl->name,pl->contr->title);
else
sprintf(buf,"Player: %s the %s",pl->name,pl->contr->own_title);
strcat(buf," ");
XDrawImageString(pl->contr->gdisp,pl->contr->win_stats,
pl->contr->gc_stats,10,10,buf,strlen(buf));
}
#endif /* SET_TITLE */
void rangetostring(object *pl,char *obuf)
{
int chosen_spell;
chosen_spell = (pl->contr->shoottype==range_magic)? pl->contr->chosen_spell :
pl->contr->chosen_item_spell;
switch(pl->contr->shoottype) {
case range_none:
strcpy(obuf,"Range: nothing");
break;
case range_bow: {
char *s;
object *op;
for (op = pl->inv; op; op=op->below)
if (op->type == BOW && QUERY_FLAG (op, FLAG_APPLIED))
break;
if(op==NULL) break;
s = query_name(op);
#if 1 /* Hack to remove (readied) from a bow description */
if (strcmp (s + strlen (s) - 10, " (readied)") == 0)
s[strlen (s) - 10] = 0;
#endif
sprintf (obuf, "Range: %s (%s)", s,
op && op->race ? op->race : "nothing");
}
break;
case range_magic:
#ifdef CASTING_TIME
if (pl->casting > -1) {
if (pl->casting == 0)
sprintf(obuf,"Range: Holding spell (%s)",
pl->spell->name);
else
sprintf(obuf,"Range: Casting spell (%s)",
pl->spell->name);
}
else
#endif
sprintf(obuf,"Range: spell (%s)",
spells[pl->contr->chosen_spell].name);
break;
case range_wand:
sprintf(obuf,"Range: wand (%s)",
pl->contr->known_spell ?
spells[pl->contr->chosen_item_spell].name : "unknown");
break;
case range_rod:
sprintf(obuf,"Range: rod (%s)",
pl->contr->known_spell ?
spells[pl->contr->chosen_item_spell].name : "unknown");
break;
case range_horn:
sprintf(obuf,"Range: horn (%s)",
pl->contr->known_spell ?
spells[pl->contr->chosen_item_spell].name : "unknown");
break;
/* range_scroll is only used for controlling golems. If the
* the player does not have a golem, reset some things.
*/
case range_scroll:
if (pl->contr->golem!=NULL)
sprintf(obuf,"Range: golem (%s)",pl->contr->golem->name);
else {
pl->contr->shoottype = range_none;
strcpy(obuf,"Range: nothing");
}
break;
case range_skill:
sprintf(obuf,"Skill: %s", pl->chosen_skill!=NULL ?
skills[pl->chosen_skill->stats.sp].name : "none");
break;
default:
strcpy(obuf,"Range: illegal");
}
pl->contr->last_known_spell = pl->contr->known_spell;
pl->contr->last_shoot=pl->contr->shoottype;
pl->contr->last_spell=chosen_spell;
}
void set_title(object *pl,char *buf)
{
if(pl->contr->last_value==-1) {
/* Eneq(@csd.uu.se): Let players define their own titles. */
if (pl->contr->own_title[0]=='\0')
sprintf(buf,"Player: %s the %s",pl->name,pl->contr->title);
else
sprintf(buf,"Player: %s the %s",pl->name,pl->contr->own_title);
}
}
void draw_stats(object *pl) {
char buff[7][MAX_BUF];
int flag[7];
int i, chosen_spell;
if(pl->type!=PLAYER) {
LOG(llevError,"Warning: draw_stats() in non-player: %s (%d)\n",
pl->name,pl->count);
return;
}
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_update_stats(pl->contr->eric_server,pl);
return;
}
for(i=0;i<7;i++)
flag[i]=0;
if(pl->contr->last_value==-1) {
flag[0]=1;
set_title(pl,buff[0]);
}
if(pl->contr->last_value==-1||pl->stats.exp!=pl->contr->last_stats.exp||
pl->contr->last_level!=pl->level) {
sprintf(buff[1],"Score: %5d Level: %d",pl->stats.exp,pl->level);
flag[1]=1;
pl->contr->last_stats.exp=pl->stats.exp;
pl->contr->last_level=pl->level;
}
if(pl->contr->last_value==-1||
pl->stats.hp!=pl->contr->last_stats.hp||
pl->stats.maxhp!=pl->contr->last_stats.maxhp||
pl->stats.sp!=pl->contr->last_stats.sp||
pl->stats.maxsp!=pl->contr->last_stats.maxsp||
pl->stats.grace!=pl->contr->last_stats.grace||
pl->stats.maxgrace!=pl->contr->last_stats.maxgrace) {
sprintf(buff[2],"Hp:%d/%d Sp:%d/%d Gr:%d/%d",
pl->stats.hp,pl->stats.maxhp,pl->stats.sp,pl->stats.maxsp,
pl->stats.grace,pl->stats.maxgrace);
flag[2]=1;
pl->contr->last_stats.hp=pl->stats.hp;
pl->contr->last_stats.maxhp=pl->stats.maxhp;
pl->contr->last_stats.sp=pl->stats.sp;
pl->contr->last_stats.maxsp=pl->stats.maxsp;
pl->contr->last_stats.grace=pl->stats.grace;
pl->contr->last_stats.maxgrace=pl->stats.maxgrace;
}
if(pl->contr->last_value==-1||
pl->stats.Dex!=pl->contr->last_stats.Dex ||
pl->stats.Con!=pl->contr->last_stats.Con ||
pl->stats.Str!=pl->contr->last_stats.Str ||
pl->stats.Int!=pl->contr->last_stats.Int ||
pl->stats.Wis!=pl->contr->last_stats.Wis ||
pl->stats.Pow!=pl->contr->last_stats.Pow ||
pl->stats.Cha!=pl->contr->last_stats.Cha) {
sprintf(buff[3],"S%2d D%2d Co%2d I%2d W%2d P%2d Ch%2d",
pl->stats.Str,pl->stats.Dex,pl->stats.Con,
pl->stats.Int,pl->stats.Wis,pl->stats.Pow,
pl->stats.Cha);
flag[3]=1;
pl->contr->last_stats.Str=pl->stats.Str;
pl->contr->last_stats.Con=pl->stats.Con;
pl->contr->last_stats.Dex=pl->stats.Dex;
pl->contr->last_stats.Int=pl->stats.Int;
pl->contr->last_stats.Wis=pl->stats.Wis;
pl->contr->last_stats.Pow=pl->stats.Pow;
pl->contr->last_stats.Cha=pl->stats.Cha;
}
if(pl->contr->last_value==-1||
pl->stats.wc!=pl->contr->last_stats.wc||
pl->stats.ac!=pl->contr->last_stats.ac||
pl->armour!=pl->contr->last_armour||
pl->stats.dam!=pl->contr->last_stats.dam) {
sprintf(buff[4],"Wc:%3d Dam:%3d Ac:%3d Arm:%3d",
pl->stats.wc,pl->stats.dam,pl->stats.ac,pl->armour);
flag[4]=1;
pl->contr->last_stats.wc=pl->stats.wc;
pl->contr->last_stats.ac=pl->stats.ac;
pl->contr->last_stats.dam=pl->stats.dam;
pl->contr->last_armour=pl->armour;
}
if(pl->contr->last_value==-1||pl->contr->last_speed!=pl->speed||
pl->stats.food!=pl->contr->last_stats.food||
pl->contr->last_weapon_sp!=pl->contr->weapon_sp) {
flag[5]=1;
if(pl->stats.food<100&&(pl->stats.food&4))
sprintf(buff[5],"Speed: %3.2f (%1.2f) Food: *%d* HUNGRY!",
pl->speed,pl->speed/pl->contr->weapon_sp,pl->stats.food);
else
sprintf(buff[5],"Speed: %3.2f (%1.2f) Food: %3d",
pl->speed,pl->speed/pl->contr->weapon_sp,pl->stats.food);
pl->contr->last_stats.food=pl->stats.food;
pl->contr->last_speed=pl->speed;
pl->contr->last_weapon_sp=pl->contr->weapon_sp;
}
chosen_spell = (pl->contr->shoottype==range_magic)? pl->contr->chosen_spell :
pl->contr->chosen_item_spell;
#ifdef CASTING_TIME
if(pl->spell_state||pl->contr->last_value==-1||
pl->contr->last_shoot!=pl->contr->shoottype||
((pl->contr->shoottype>range_bow && pl->contr->shoottype < range_size)&&
pl->contr->last_spell!=chosen_spell)) {
pl->spell_state = 0;
#else
if(pl->contr->last_value==-1||pl->contr->last_shoot!=pl->contr->shoottype||
((pl->contr->shoottype>range_bow && pl->contr->shoottype < range_size)&&
pl->contr->last_spell!=chosen_spell)) {
#endif
flag[6]=1;
rangetostring(pl,buff[6]);
}
if(pl->contr->shoottype==range_skill) {
flag[6]=1;
rangetostring(pl,buff[6]);
}
for(i=0;i<7;i++)
if(flag[i]) {
strcat(buff[i]," "); /* In case it became shorter */
XDrawImageString(pl->contr->gdisp,pl->contr->win_stats,
pl->contr->gc_stats,10,i*14+10, buff[i],strlen(buff[i]));
}
if(pl->contr->last_value!= -1)
draw_message_window(pl); /* Update bars */
pl->contr->last_value=pl->value;
}
void draw_all_info(object *pl) {
int i;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_all_info");
return;
}
XClearWindow(pl->contr->gdisp,pl->contr->win_info);
if ((pl->contr->scroll) && (pl->contr->infofull)) {
int j;
for (i=0; i<pl->contr->infolines; i++) {
j = (pl->contr->infopos+i + 1) % pl->contr->infolines;
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
pl->contr->gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
pl->contr->info[j], strlen(pl->contr->info[j]));
}
}
else
for(i=0;i<pl->contr->infolines;i++)
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
pl->contr->gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
pl->contr->info[i],strlen(pl->contr->info[i]));
}
#define draw_inv_face(pl,win,gc,x,y,face) \
{ \
if (pl->color_pixmaps) \
{ \
XSetClipMask(pl->gdisp, gc, pl->masks[(face)]); \
XSetClipOrigin(pl->gdisp, gc, x, (y) - 24); \
XCopyArea(pl->gdisp, pl->pixmaps[(face)], win, gc, 0, 0, 24, 24, \
(unsigned int) (x), (unsigned int) ((y) - 24)); \
} \
else if(pl->use_pixmaps) \
{ \
XSetClipMask(pl->gdisp, gc, pl->pixmaps[(face)]); \
XSetClipOrigin(pl->gdisp, gc, x, (y) - 24); \
XCopyPlane(pl->gdisp,pl->pixmaps[(face)],win,gc,0,0,24,24, \
(unsigned int) (x),(unsigned int) ((y) - 24),1); \
} \
else \
{ \
XChar buf; \
buf = FontindexToXChar((Fontindex) (face)); \
XDrawString16(pl->gdisp,win,gc,x,y,&buf,1); \
} \
}
/* This routine has gotten a little more complicated with the addition
* of color pixmaps (XPM). This is because normally, drawing a face
* would overwrite the old face drawn there. However, with shape masks,
* this does not happen. So in order to keep things looking right, a
* XClearArea is called to clear the face area before draw_face is
* called. This is only done if the user is using color pixmaps.
* Mark Wedel (master@rahul.net)
*/
/* Also, I changed the start height values to start at 16 + 24*(other stuff)
* This is because the draw_face calls start at 40 + 24*(other_stuff).
* The draw_face macro then subtracts 24. 40-24 = 16. Without this
* changed, not all information was being erased (This is because of
* the change to use XClearArea instead of overdrawing the area with
* another face. The later case did not look nice when the color
* pixmap (XPM) additions. MSW (master@rahul.net)
*/
void draw_inventory(object *pl) {
signed short items;
int i,j;
object *tmp;
char buf[MAX_BUF], *obj_name, name_buf[MAX_BUF];
player *p=pl->contr;
if(pl->type!=PLAYER)
return;
if(p->freeze_inv)
return;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
LOG(llevDebug,"Warning, draw_inventory called in eric server mode.\n");
/* esrv_foo(pl->contr->eric_server,"draw_inventory");*/
return;
}
for(tmp=pl->inv,items=0;tmp!=NULL;tmp=tmp->below)
if (show_what_object(tmp,p->show_what))
items++;
if(p->scroll_inv>(items - p->inv_size))
p->scroll_inv=items-p->inv_size;
if(p->scroll_inv<0)
p->scroll_inv=0;
if(p->last_weight!=pl->weight+pl->carrying) {
p->last_weight=pl->weight+pl->carrying;
sprintf(buf,"Inventory%s: (%s)",
(p->show_what == show_applied ? " (applied) " :
(p->show_what == show_unapplied ? " (unapplied) " :
(p->show_what == show_unpaid ? " (unpaid) " :
(p->show_what == show_cursed ? " (cursed) ":
(p->show_what == show_magical ? " (magical) " :
(p->show_what == show_nonmagical ? " (nonmagical) " : "")))))),
query_weight(pl));
XDrawImageString(p->gdisp,p->win_inv,
p->gc_inv_text,8,13,buf,strlen(buf));
}
for(tmp=pl->inv,i=0;tmp!=NULL;tmp=tmp->below,i++) {
if (!show_what_object(tmp, p->show_what))
{
i--;
continue;
}
if(i-p->scroll_inv>=p->inv_size||i<p->scroll_inv)
continue;
if(p->inv_face[i-p->scroll_inv]!=tmp->face->number) {
p->inv_face[i-p->scroll_inv]=tmp->face->number;
if (p->color_pixmaps)
XClearArea(p->gdisp, p->win_inv, 4, 16+24*(i-p->scroll_inv), 24,24,False);
draw_face(p,p->win_inv,p->gc_inv_icon,4,40+24*(i-p->scroll_inv),tmp->face->number);
}
obj_name = query_name(tmp);
/* Name buf is just the object name and weight. Both need to be stored,
* otherwise this would not always be updated (when dropping a short
* sword with another below it, the weight of the next short sword would
* be shown as the same as the original.
*/
strcpy(name_buf,obj_name);
strcat(name_buf,query_weight(tmp));
if(p->inv_name[i-p->scroll_inv] &&
!strcmp(p->inv_name[i-p->scroll_inv],name_buf))
continue;
sprintf(buf,p->format_inv,obj_name,query_weight(tmp));
if (p->show_inv_icon) {
XClearArea(p->gdisp, p->win_inv, 32, 16+24*(i-p->scroll_inv), 24,24,False);
if (QUERY_FLAG(tmp, FLAG_INV_LOCKED))
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_lock_face->number);
if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)) {
if (QUERY_FLAG(tmp, FLAG_DAMNED)) {
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_damn_face->number);
} else {
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_curse_face->number);
}
}
if (QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL) &&
!QUERY_FLAG(tmp,FLAG_IDENTIFIED) && !QUERY_FLAG(tmp,FLAG_BEEN_APPLIED))
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_magic_face->number);
if (QUERY_FLAG(tmp, FLAG_APPLIED))
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_equip_face->number);
if (QUERY_FLAG(tmp, FLAG_UNPAID))
draw_inv_face(p, p->win_inv, p->gc_inv_status_icon,32, 40+24*(i-p->scroll_inv),
inv_unpaid_face->number);
} /* if show_inv_icon */
if (p->inv_name[i-p->scroll_inv])
free_string(p->inv_name[i-p->scroll_inv]);
p->inv_name[i-p->scroll_inv] = add_string(name_buf);
if (p->show_inv_icon)
XDrawImageString(p->gdisp,p->win_inv,
p->gc_inv_text,60,34+24*(i-p->scroll_inv)
,buf,strlen(buf));
else
XDrawImageString(p->gdisp,p->win_inv,
p->gc_inv_text,32,34+24*(i-p->scroll_inv)
,buf,strlen(buf));
}
if((i-p->scroll_inv)<=p->nrofdrawn_inv) {
int start_height=16+24*(i-p->scroll_inv);
int height;
for(j=i;(j-p->scroll_inv)<=p->nrofdrawn_inv&&
(j-p->scroll_inv)<p->inv_size;j++) {
p->inv_face[j-p->scroll_inv]=blank_face->number;
p->inv_name[j-p->scroll_inv]=NULL;
}
if(p->inv_size<p->nrofdrawn_inv)
height=p->inv_size*24;
else
height=p->nrofdrawn_inv*24;
XClearArea(p->gdisp,p->win_inv,0,start_height,
p->invhint.width-23,height*24,0);
}
if(i<p->inv_size)
i=p->inv_size;
p->nrofdrawn_inv=i;
j =((int)p->inv_size * (int)p->barlength_inv / i);
if(p->scrollsize_inv!=j||
p->last_scroll_inv!=p->scroll_inv)
{ /* Change the scrollbar if different */
int offset = (int)p->scroll_inv * (int)p->barlength_inv / i;
XClearArea(p->gdisp,p->win_inv,p->invhint.width-20,17+p->scrollstart_inv,
16,p->scrollsize_inv,0);
p->scrollsize_inv=j;
p->scrollstart_inv=offset;
p->last_scroll_inv=p->scroll_inv;
XFillRectangle(p->gdisp,p->win_inv,p->gc_inv_text,
p->invhint.width-20,17+offset,16,p->scrollsize_inv);
}
}
void draw_inventory_faces(object *pl) {
int i,items;
object *tmp, *inv=pl->inv;
player *p=pl->contr;
if(p->freeze_inv)
return;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
/* This gets to be a bit too verbose */
/* LOG(llevDebug,"Warning, draw_inventory_faces has no effect.\n");*/
/* esrv_foo(pl->contr->eric_server,"draw_inventory_faces");*/
return;
}
for(tmp=inv,items=0;tmp!=NULL;tmp=tmp->below)
if (show_what_object(tmp, p->show_what))
items++;
if(p->scroll_inv>items-p->inv_size)
p->scroll_inv=items-p->inv_size;
if(p->scroll_inv<0)
p->scroll_inv=0;
for(tmp=inv,i=0;tmp!=NULL;tmp=tmp->below) {
if (show_what_object(tmp, p->show_what)) {
if (!(i-p->scroll_inv>=p->inv_size || i<p->scroll_inv ||
p->inv_face[i-p->scroll_inv]==tmp->face->number)) {
p->inv_face[i-p->scroll_inv]=tmp->face->number;
if (p->color_pixmaps)
XClearArea(p->gdisp, p->win_inv, 4, 16+24*(i-p->scroll_inv), 24,24,False);
draw_face(p,p->win_inv,p->gc_inv_icon,4,40+24*(i-p->scroll_inv),tmp->face->number);
}
i++;
}
}
if((i-p->scroll_inv)<=p->nrofdrawn_inv) {
int start_height = 16 + 24*(i-p->scroll_inv),height;
if (p->inv_size<p->nrofdrawn_inv)
height = p->inv_size * 24;
else
height = p->nrofdrawn_inv * 24;
XClearArea(p->gdisp, p->win_inv, 0, start_height, 28, height, False);
}
}
void draw_all_inventory(object *pl) {
int i;
player *p=pl->contr;
for(i=0;i<p->inv_size;i++) {
p->inv_face[i]=blank_face->number;
p->inv_name[i]=NULL;
}
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
LOG(llevDebug, "Warning, draw_all_inventory called in eric server mode\n");
/* esrv_foo(pl->contr->eric_server,"draw_all_inventory");*/
return;
}
XClearWindow(p->gdisp,p->win_inv);
XDrawRectangle(p->gdisp,p->win_inv,
p->gc_inv_text,p->invhint.width-22,15,20,p->barlength_inv+4);
p->scrollsize_inv=1,p->scrollstart_inv=1,
p->nrofdrawn_inv=0;
p->last_weight= (-1);
p->freeze_inv=0;
draw_inventory(pl);
}
void draw_look(object *pl) {
signed short i,j,items;
object *tmp,*top;
char buf[MAX_BUF];
player *p=pl->contr;
if(p->freeze_look)
return;
if(QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY)
return;
if(out_of_map(pl->map,pl->x,pl->y))
return;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_draw_look(pl);
return;
}
/* Eneq(@csd.uu.se): Display container or look. */
if (pl->container==NULL)
for(top=get_map_ob(pl->map,pl->x,pl->y);top!=NULL&&top->above!=NULL;
top=top->above);
else
top = pl->container->inv;
for(tmp=top,items=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below)
if LOOK_OBJ(tmp)
items++;
if(p->scroll_look>items-p->look_size)
p->scroll_look=items-p->look_size;
if(p->scroll_look<0)
p->scroll_look=0;
XSetForeground(p->gdisp,p->gc_look_text,
p->gforeground);
for(tmp=top,i=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,
FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below,i++)
{
if (!LOOK_OBJ(tmp)) {
i--;
continue;
}
/* If we have drawn all that is possible, break out of this loop */
if ( i- p->scroll_look>=p->look_size) break;
if (i<p->scroll_look)
continue;
if(p->look_face[i-p->scroll_look]!=tmp->face->number) {
p->look_face[i-p->scroll_look]=tmp->face->number;
if (p->color_pixmaps)
XClearArea(p->gdisp, p->win_look, 4, 16+24*(i-p->scroll_look), 24,24,False);
draw_face(p,p->win_look,p->gc_look_icon,4,40+24*(i-p->scroll_look),tmp->face->number);
}
if(QUERY_FLAG(tmp, FLAG_NO_PICK)) {
char *cp;
strncpy(buf,query_name(tmp),p->look_chars); /* Don't worry about screenwidth */
buf[p->look_chars]='\0';
cp=strchr(buf,'\0');
/* We need to pad the string with spaces, so that it overwrites the
* previous item name printed in the window.
*/
if((sint16)strlen(buf)<p->look_chars)
memset((void *)cp,' ',p->look_chars-strlen(buf));
buf[p->look_chars]='\0';
} else
sprintf(buf,p->format_look,query_name(tmp),query_weight(tmp));
if(!p->look_name[i-p->scroll_look] || strcmp(buf,p->look_name[i-p->scroll_look])) {
if (p->look_name[i-p->scroll_look])
free_string(p->look_name[i-p->scroll_look]);
p->look_name[i-p->scroll_look] = add_string(buf);
XDrawImageString(p->gdisp,p->win_look,
p->gc_look_text,32,34+24*(i-p->scroll_look)
,buf,strlen(buf));
}
}
/* If there are not enough items to fill in the display area,
* then set the unused ares to nothing.
*/
if(items<p->nrofdrawn_look) {
int start_height=16+24*(i-p->scroll_look);
int height;
for(j=i;(j-p->scroll_look)<=p->nrofdrawn_look&&
(j-p->scroll_look)<p->look_size;j++) {
p->look_name[j-p->scroll_look]=NULL;
p->look_face[j-p->scroll_look]=blank_face->number;
}
if(p->look_size<p->nrofdrawn_look)
height=p->look_size*24;
else
height=p->nrofdrawn_look*24;
XClearArea(p->gdisp,p->win_look,0,start_height,
p->lookhint.width-23,height,0);
}
p->nrofdrawn_look=items;
if(items<p->look_size)
items=p->look_size;
j =((int)p->look_size * (int)p->barlength_look / items);
/* draw the scrollbar now */
if(p->scrollsize_look!=(unsigned short) j||
p->last_scroll_look!=p->scroll_look) {
int offset =(int)p->scroll_look * (int)p->barlength_look / items;
XClearArea(p->gdisp,p->win_look,p->lookhint.width-20,
17+p->scrollstart_look,16,p->scrollsize_look,0);
p->scrollsize_look=j;
p->scrollstart_look=offset;
p->last_scroll_look=p->scroll_look;
XFillRectangle(p->gdisp,p->win_look,p->gc_look_text,
p->lookhint.width-20,17+offset,16,p->scrollsize_look);
}
}
/* This only draws the look faces. Maybe used for animations?
*/
void draw_look_faces(object *pl) {
int i,items;
object *tmp,*top;
player *p=pl->contr;
if(p->freeze_look)
return;
if(QUERY_FLAG(pl, FLAG_REMOVED)||out_of_map(pl->map,pl->x,pl->y))
return;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_look_faces");
return;
}
for(top=(pl->container?pl->container->inv:get_map_ob(pl->map,pl->x,pl->y));
top!=NULL&&top->above!=NULL;
top=top->above);
for(tmp=top,items=0;(tmp!=NULL)&&(!(tmp->above&&
QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR)); tmp=tmp->below)
if LOOK_OBJ(tmp)
items++;
/* If the number of objects is different than what was drawn
* before, then we should also draw the names. So just call
* draw_look to do it.
*/
if (p->nrofdrawn_look!=items) {
draw_look(pl);
return;
}
if(p->scroll_look>items-p->look_size)
p->scroll_look=items-p->look_size;
if(p->scroll_look<0)
p->scroll_look=0;
for(tmp=top,i=0;(tmp!=NULL)&&(!(tmp->above&&QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))||QUERY_FLAG(tmp,FLAG_IS_FLOOR));tmp=tmp->below,i++) {
if (!LOOK_OBJ(tmp)) {
i--;
continue;
}
if(i-p->scroll_look>=p->look_size) break;
if (i<p->scroll_look) continue;
if(p->look_face[i-p->scroll_look]!=tmp->face->number) {
p->look_face[i-p->scroll_look]=tmp->face->number;
if (p->color_pixmaps)
XClearArea(p->gdisp, p->win_look, 4, 16+24*(i-p->scroll_look), 24,24,False);
draw_face(p,p->win_look,p->gc_look_icon,4,40+24*(i-p->scroll_look),tmp->face->number);
}
}
/* No need to do any erasing, because if the number of objects has
* decreased, the draw_look function was called instead.
*/
}
void draw_all_look(object *pl) {
int i;
player *p=pl->contr;
for(i=0;i<p->look_size;i++) {
p->look_face[i]=blank_face->number;
p->look_name[i]=NULL;
}
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_draw_look(pl);
return;
}
XClearWindow(p->gdisp,p->win_look);
XDrawRectangle(p->gdisp,p->win_look,p->gc_look_text,
p->lookhint.width-22,15,20,p->barlength_look+4);
p->scrollsize_look=1,p->scrollstart_look=1,
p->nrofdrawn_look=0;
if (!pl->container)
XDrawImageString(p->gdisp,p->win_look,
p->gc_look_text,8,13,"You see: ",13);
else
XDrawImageString(p->gdisp,p->win_look,
p->gc_look_text,8,13,"In container:",13);
p->freeze_look=0;
draw_look(pl);
}
#define MAX_BARS_MESSAGE 80
static void draw_stat_bar(object *pl, int bar_pos,
int height, int old_height,
int is_alert, int old_is_alert)
{
if(height==old_height && is_alert==old_is_alert) /* nothing changed */
return;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_stat_bar");
return;
}
if(height!=MAX_BARS_MESSAGE) /* clear the top of the bar */
XClearArea(pl->contr->gdisp,pl->contr->win_message,
bar_pos, 4,
10, MAX_BARS_MESSAGE-height,
0);
if(height==0) /* empty bar */
return;
if(is_alert && pl->contr->iscolor) /* this should have its own gc */
XSetForeground(pl->contr->gdisp,pl->contr->gc_look_text,
pl->contr->discolor[3].pixel);
XFillRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,
bar_pos, 4+MAX_BARS_MESSAGE-height,
10, height);
if(is_alert && pl->contr->iscolor)
XSetForeground(pl->contr->gdisp,pl->contr->gc_look_text,
pl->contr->gforeground);
}
void draw_message_window(object *pl) {
int bar,is_alert;
/* draw hp bar */
if(pl->stats.maxhp>0)
{
bar=(pl->stats.hp*MAX_BARS_MESSAGE)/pl->stats.maxhp;
if(bar<0)
bar=0;
is_alert=(pl->stats.hp <= pl->stats.maxhp/4);
}
else
{
bar=0;
is_alert=0;
}
draw_stat_bar(pl,20,
bar,pl->contr->scrollsize_hp,
is_alert,pl->contr->scrollhp_alert);
pl->contr->scrollsize_hp=bar;
pl->contr->scrollhp_alert=is_alert;
/* draw sp bar. spellpoints can go above max
* spellpoints via supercharging with the transferrance spell,
* or taking off items that raise max spellpoints.
*/
if (pl->stats.sp>pl->stats.maxsp)
bar = MAX_BARS_MESSAGE;
else
bar=(pl->stats.sp*MAX_BARS_MESSAGE)/pl->stats.maxsp;
if(bar<0)
bar=0;
is_alert=(pl->stats.sp <= pl->stats.maxsp/4);
draw_stat_bar(pl,60,
bar,pl->contr->scrollsize_sp,
is_alert,pl->contr->scrollsp_alert);
pl->contr->scrollsize_sp=bar;
pl->contr->scrollsp_alert=is_alert;
/* draw grace bar. grace can go above max or below min
*/
if (pl->stats.grace>pl->stats.maxgrace)
bar = MAX_BARS_MESSAGE;
else
bar=(pl->stats.grace*MAX_BARS_MESSAGE)/pl->stats.maxgrace;
if(bar<0)
bar=0;
is_alert=(pl->stats.grace <= pl->stats.maxgrace/4);
draw_stat_bar(pl,100,
bar,pl->contr->scrollsize_grace,
is_alert,pl->contr->scrollgrace_alert);
pl->contr->scrollsize_grace=bar;
pl->contr->scrollgrace_alert=is_alert;
/* draw food bar */
bar=(pl->stats.food*MAX_BARS_MESSAGE)/999;
if(bar<0)
bar=0;
is_alert=(pl->stats.food <= 999/4);
draw_stat_bar(pl,140,
bar,pl->contr->scrollsize_food,
is_alert,pl->contr->scrollfood_alert);
pl->contr->scrollsize_food=bar;
pl->contr->scrollfood_alert=is_alert;
}
void xwritedown(object *pl,char *txt,int x) {
int y=13;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"xwritedown");
return;
}
for(;*txt!='\0';txt++,y+=13)
XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,x,y,txt,1);
}
void draw_all_message(object *pl) {
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
LOG(llevDebug,"draw_all_message called in eric_server mode");
return;
}
XClearWindow(pl->contr->gdisp,pl->contr->win_message);
pl->contr->scrollsize_hp=pl->contr->scrollsize_sp=
pl->contr->scrollsize_food=pl->contr->scrollsize_grace=0;
xwritedown(pl,"HP",06);
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,18,2,14,MAX_BARS_MESSAGE+4);
xwritedown(pl,"Mana",46);
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,58,2,14,MAX_BARS_MESSAGE+4);
xwritedown(pl,"Grace",86);
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,98,2,14,MAX_BARS_MESSAGE+4);
xwritedown(pl,"Food",126);
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,138,2,14,MAX_BARS_MESSAGE+4);
#ifdef USE_BUTTONS
{
int i;
for (i=0;i<NUMDIRBUTTS;i++) {
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,dirX[i],dirY[i],
dirW,18);
XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,dirX[i]+2,dirY[i]+14,
dirnames[i],2);
}
for (i=0;i<NUMOPBUTTS;i++) {
XDrawImageString(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,opX[i]+2,opY[i]+14,
opnames[i],8);
XDrawRectangle(pl->contr->gdisp,pl->contr->win_message,
pl->contr->gc_look_text,opX[i],opY[i],
48,18);
}
}
#endif
draw_message_window(pl);
}
/****************************************************************************
* Following group is a set of functions that deal with display information
* to the player/screen.
*
* Cleaned up so that only a few functions are actually needed - just
* pass different values to it.
*
****************************************************************************/
static void print_message(int colr, object *pl,const char *tmp);
static void draw_info(object *pl,const char *str);
/* Following prints out the contents of one of the buffer structures,
* and clears the string.
*/
void flush_output_element(object *pl, Output_Buf *outputs)
{
char tbuf[MAX_BUF];
if (outputs->buf==NULL) return;
sprintf(tbuf,"%d times %s", outputs->count, outputs->buf);
print_message(NDI_BLACK, pl, tbuf);
free_string(outputs->buf);
outputs->buf=NULL;
outputs->first_update=0; /* This way, it will be reused */
}
/* Following checks the various buffers in the player structure and
* other things, and stores/prints/whatever's the data, as appropriate.
*/
void check_output_buffers(object *pl, char *buf)
{
int i, oldest=0;
if (pl->contr->outputs_count<2) {
print_message(NDI_BLACK, pl, buf);
return;
}
else {
for (i=0; i<NUM_OUTPUT_BUFS; i++) {
if (pl->contr->outputs[i].buf &&
!strcmp(buf, pl->contr->outputs[i].buf)) break;
else if (pl->contr->outputs[i].first_update <
pl->contr->outputs[oldest].first_update)
oldest=i;
}
/* We found a match */
if (i<NUM_OUTPUT_BUFS) {
pl->contr->outputs[i].count++;
if (pl->contr->outputs[i].count>=pl->contr->outputs_count) {
flush_output_element(pl, &pl->contr->outputs[i]);
}
}
/* No match - flush the oldest, and put the new one in */
else {
flush_output_element(pl, &pl->contr->outputs[oldest]);
pl->contr->outputs[oldest].first_update = pticks;
pl->contr->outputs[oldest].count = 1;
if (pl->contr->outputs[oldest].buf!=NULL)
free_string(pl->contr->outputs[oldest].buf);
pl->contr->outputs[oldest].buf = add_string(buf);
}
}
}
/*
* new_draw_info:
*
* flags is various flags - mostly color, plus a few specials.
*
* pri is priority. It is a little odd - the lower the value, the more
* important it is. Thus, 0 gets sent no matter what. Otherwise, the
* value must be less than the listening level that the player has set.
* Unfortunately, there is no clear guideline on what each level does what.
*
* pl can be passed as NULL - in fact, this will be done if NDI_ALL is set
* in the flags.
*
*/
void new_draw_info(int flags,int pri, object *pl, const char *buf)
{
if (flags & NDI_ALL) {
player *tmppl;
for (tmppl=first_player; tmppl!=NULL; tmppl=tmppl->next)
new_draw_info((flags & ~NDI_ALL), pri, tmppl->ob, buf);
if (pri<9) info_all_sockets((char*)buf);
return;
}
if(!pl || (pl->type==PLAYER && pl->contr==NULL)) {
/* Write to the socket? */
print_message(0, NULL, buf);
return;
}
if (pl->type!=PLAYER) return;
if (pri>=pl->contr->listening) return;
if ((flags&NDI_COLOR_MASK)==NDI_BLACK && !(flags &NDI_UNIQUE)) {
/* following prints stuff out, as appropriate */
check_output_buffers(pl, (char*)buf);
}
else {
print_message(flags&NDI_COLOR_MASK, pl, buf);
}
}
/* This is a pretty trivial function, but it allows us to use printf style
* formatting, so instead of the calling function having to do it, we do
* it here. IT may also have advantages in the future for reduction of
* client/server bandwidth (client could keep track of various strings
*/
void new_draw_info_format(int flags, int pri,object *pl, char *format, ...)
{
char buf[MAX_BUF];
va_list ap;
va_start(ap, format);
vsprintf(buf, format, ap);
va_end(ap);
new_draw_info(flags, pri, pl, buf);
}
void new_info_map(int color, mapstruct *map, char *str) {
player *pl;
for(pl = first_player; pl != NULL; pl = pl->next)
if(pl->ob != NULL && pl->ob->map == map) {
new_draw_info(color, 0, pl->ob, str);
}
}
/****************************************************************************
print_message : This routine prints out the character string in tmp on the
info window. If in color mode, then the text will show up in
a color specified by the variable colr. If Black and white
mode, then it prints a line of "="s before and after the
messsage.
This has been changed around - this is now a front end to
draw_info. draw_info should never be called directly, except
by this functin. Likewise, this function should only be
called by a few functions above (new_draw_info,
check_output_buffers)
****************************************************************************/
static void print_message(int colr, object *pl,const char *tmp) {
if(!pl || (pl->type==PLAYER && pl->contr==NULL)) {
#ifdef SERVER
if(active_socket != (sockets *) NULL)
draw_socket(active_socket->fd,tmp);
else
#endif
fprintf(logfile,"%s\n",tmp);
return;
}
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_print_msg(pl->contr->eric_server,colr,(char*) tmp);
return;
}
if(tmp == (char *) NULL) {
tmp="[NULL]";
}
if (colr!=NDI_BLACK) {
if (pl->contr->iscolor) {
XSetForeground(pl->contr->gdisp,pl->contr->gc_info,
pl->contr->discolor[colr].pixel);
draw_info(pl,tmp);
XSetForeground(pl->contr->gdisp,pl->contr->gc_info,
pl->contr->discolor[0].pixel);
}
else {
draw_info(pl,"==========================================");
draw_info(pl,tmp);
draw_info(pl,"==========================================");
}
}
else
draw_info(pl, tmp);
}
/* This entire function won't be needed once true client/server happens. */
static void draw_info(object *pl,const char *str) {
static char blanks[]=" ";
char *cp;
/* Following should be removed - all message handling to client should be
* done in print_message, above
*/
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
LOG(llevError,"In draw_info, new client/server function will be called\n");
esrv_drawinfo(pl->contr->eric_server,str);
return;
}
if((cp=strchr(str,'\n'))!=NULL) {
char *obuf = (char *) malloc(sizeof(char) * (strlen(str) + 2)), *buf = obuf;
strcpy(buf,str);
do {
if ((cp = strchr(buf, '\n'))) {
*cp='\0';
draw_info(pl,buf);
buf = cp +1;
} else
draw_info(pl, buf);
} while (cp!=NULL);
free(obuf);
return;
}
/* Lets do the word wrap for messages - MSW (master@rahul.net) */
if ((int)strlen(str) >= (int)pl->contr->infochars) {
int i=pl->contr->infochars-1;
/* i=last space (or ')' for armor. Wrap armor, because
otherwise, the two sets of ()() can be about half the line */
while ((str[--i]!=' ') && (str[i]!=')') && (i!=0)) ;
/* if i==0, string has no space. Just let it be truncated */
if (i!=0) {
char *buf = (char *)malloc(sizeof(char)*(i+2));
int j;
i++; /* want to keep the ')'. This also keeps
the space, but that really doesn't matter */
strncpy(buf, str, i);
buf[i]='\0';
draw_info(pl, buf);
free(buf);
for (j=i; j < (int)strlen(str); j++) /* if the wrap portion is */
if (str[j]!=' ') break; /* only space, don't wrap it*/
if ((((strlen(str)-i)!=1) || (str[i]!='.')) && (j!=strlen(str)))
draw_info(pl, (str+i));
return;
}
}
strncpy(pl->contr->info[pl->contr->infopos],str,pl->contr->infochars);
pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
pl->contr->gc_info,FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,
pl->contr->info[pl->contr->infopos],
strlen(pl->contr->info[pl->contr->infopos]));
pl->contr->infopos = (pl->contr->infopos+1)% pl->contr->infolines ;
if(++(pl->contr->infoline)>=pl->contr->infolines){
if (pl->contr->scroll) {
XCopyArea(pl->contr->gdisp,pl->contr->win_info,pl->contr->win_info,
pl->contr->gc_info,0,FONTHEIGHT,pl->contr->infochars*FONTWIDTH,
pl->contr->infolines*FONTHEIGHT,0,0);
pl->contr->infoline--;
}
else
pl->contr->infoline=0;
pl->contr->infofull=1;
}
strncpy(pl->contr->info[pl->contr->infopos],blanks,pl->contr->infochars);
pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,
pl->contr->gc_info,FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,blanks,strlen(blanks));
if(pl->contr->writing) {
strncpy(pl->contr->info[pl->contr->infopos],
pl->contr->write_buf,pl->contr->infochars);
pl->contr->info[pl->contr->infopos][pl->contr->infochars] = '\0';
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,
pl->contr->write_buf,pl->contr->writing);
}
if ((int)strlen(str) > (int)pl->contr->infochars)
draw_info(pl,str+pl->contr->infochars);
}
/****************************************************************************
*
* Following set of functions are used when entering commands, passwords,
* or any other thing that takes several characters.
*
* This will not be needed for new client/server mode
*
****************************************************************************/
void delete_ch(object *pl) {
if(pl->contr->no_echo&&pl->contr->writing==1) /* Can't delete that prompt */
return;
pl->contr->write_buf[--pl->contr->writing]='\0';
pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0';
if(pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_write_ch(pl->contr->eric_server,8);
return;
}
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
(pl->contr->writing+1)*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT," ",1);
}
void write_ch(object *pl,unsigned char key)
{
char *c;
if ((key < 32 || key > 127) && key != 8)
return;
if(pl->contr->writing>=pl->contr->infochars)
return;
if(key==8||key==127) {
delete_ch(pl->contr->ob);
return;
}
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_write_ch(pl->contr->eric_server,
pl->contr->no_echo ? '?' : key);
pl->contr->write_buf[pl->contr->writing]=key;
pl->contr->writing++;
return;
}
c= &pl->contr->write_buf[pl->contr->writing];
pl->contr->write_buf[pl->contr->writing]=key;
if(pl->contr->writing>=pl->contr->infochars)
return;
pl->contr->write_buf[pl->contr->writing]=key;
pl->contr->info[pl->contr->infoline][pl->contr->writing] =
pl->contr->no_echo? '?': key;
pl->contr->writing++;
pl->contr->write_buf[pl->contr->writing]='\0';
pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0'; pl->contr->info[pl->contr->infoline][pl->contr->writing]='\0';
if(pl->contr->no_echo)
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
pl->contr->writing*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,"?",1);
else
XDrawImageString(pl->contr->gdisp,pl->contr->win_info,pl->contr->gc_info,
pl->contr->writing*FONTWIDTH,(pl->contr->infoline+1)*FONTHEIGHT,c,1);
}
void refresh_win_info(object *op) {
draw_all_info(op);
}
void clear_win_info(object *op) {
int i;
/* don't clear if in scroll mode MSW (master@rahul.net) */
if((op->type==PLAYER) && (op->contr->scroll)) return;
if (op->type == PLAYER && op->contr->eric_server > 0) {
esrv_foo(op->contr->eric_server,"clear_win_info");
return;
}
for(i=0;i<op->contr->infolines;i++) {
(void) memset((void *)op->contr->info[i],' ',op->contr->infochars);
op->contr->info[i][op->contr->infochars]='\0';
}
XClearWindow(op->contr->gdisp,op->contr->win_info);
/*refresh_win_info(op); */
op->contr->infoline=0;
op->contr->infopos=0;
}
void refresh(object *pl) {
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"refresh");
return;
}
XClearWindow(pl->contr->gdisp,pl->contr->win_game);
if(pl->contr->viewmap) {
draw_map(pl);
return;
}
refresh_map(pl->map);
(void)memset((void *)pl->contr->drawn,'\0',
sizeof(New_Face*)*(WINRIGHT-WINLEFT+1)*(WINLOWER-WINUPPER+1));
draw(pl);
}
#define CD_DRAW_MAP
/* #define ALTERNATE_MM */ /* Small changes by Frank...experimental */
void draw_dots(object *op) {
player *pl;
if (op->type == PLAYER && op->contr->eric_server > 0) {
esrv_foo(op->contr->eric_server,"draw_dots");
return;
}
op->contr->viewmap^=2;
if(op->contr->viewmap&2) {
int i=0;
XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
for(pl=first_player;pl!=NULL;pl=pl->next) {
if(pl->ob->map!=op->map)
break;
#ifdef CD_DRAW_MAP
XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
2+op->contr->mapres*(pl->ob->x - op->contr->mapxmin),
2+op->contr->mapres*(pl->ob->y - op->contr->mapymin),
op->contr->mapres,op->contr->mapres);
op->contr->mapdelx[i]=pl->ob->x - op->contr->mapxmin;
op->contr->mapdely[i]=pl->ob->y - op->contr->mapymin;
i++;
#else /* CD_DRAW_MAP */
XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
2+op->contr->mapres*pl->ob->x,
2+op->contr->mapres*pl->ob->y,
op->contr->mapres,op->contr->mapres);
op->contr->mapdelx[i]=pl->ob->x,
op->contr->mapdely[i]=pl->ob->y,
i++;
#endif /* CD_DRAW_MAP */
}
op->contr->mapdelx[i]= -1;
} else {
int i;
XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
for(i=0;op->contr->mapdelx[i]!=-1;i++)
XFillRectangle(op->contr->gdisp,op->contr->win_game,op->contr->gc_game,
2+op->contr->mapres*op->contr->mapdelx[i],
2+op->contr->mapres*op->contr->mapdely[i],
op->contr->mapres,op->contr->mapres);
XSetForeground(op->contr->gdisp,op->contr->gc_game,op->contr->gforeground);
XSetBackground(op->contr->gdisp,op->contr->gc_game,op->contr->gbackground);
}
}
#ifndef CD_DRAW_MAP
void draw_map(object *pl) {
int res,x,y;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_map");
return;
}
pl->contr->viewmap=1;
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XClearWindow(pl->contr->gdisp,pl->contr->win_game);
res=(WINRIGHT-WINLEFT+1)*24/
(pl->map->mapx>pl->map->mapy?pl->map->mapx:pl->map->mapy);
pl->contr->mapres=res;
for(x=0;x<pl->map->mapx;x++)
for(y=0;y<pl->map->mapy;y++)
if(!blocks_view(pl->map,x,y)&&!wall(pl->map,x,y))
XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,2+res*x,2+res*y,res,res);
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
}
#else /* CD_DRAW_MAP */
void magic_mapping_mark(object *pl, char *map_mark, int strength);
void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py);
/* The following function is a lot messier than it really should be,
* but there is no real easy solution.
*
* One of the main causes is uses the crossfire font to draw the stipple
* pattern. This then means that the excess needs to be erased. As things
* stand now, the excess is erased, and things look ok.
*
* Also, display on black and white system is still not as good (useful)
* as on a color system. However, things are not too bad. At present, there
* are 4 possible outputs: White, meaning a wall, black, meaning
* nothing (or only floor), grey (stippled pattern), for any other objects
* that do not have a black foreground, and another stippled patern for
* objects that do have a black foreground.
*
* Display of the stipples is not perfect. One of the stipples is just
* a checkerboard pattern. IF the resolution is odd, and two of these
* are placed together, little imperfections in the matching shows up.
* However, it doesn't affect the usefulness of the display much, and
* I don't want to add more code to deal with making the stipple perfect.
* This is because the second stipple pattern used has a different
* repeat rate
*
* Mark Wedel (master@rahul.net)
*/
void draw_map(object *pl)
{
int res,x,y;
char *map_mark = (char *) malloc(pl->map->mapx * pl->map->mapy);
int xmin = pl->map->mapx, xmax = 0, ymin = pl->map->mapy, ymax = 0;
XWindowAttributes win_info;
memset(map_mark, 0, pl->map->mapx * pl->map->mapy);
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_map");
return;
}
#if 0 /* Hmm, why did this fail completely? I want to see all of it! */
if (WIZPASS(pl)) /* Toggle WIZPASS with 'W' in DM-mode */
{
(void) memset((void *)map_mark, 1, pl->map->mapx * pl->map->mapy);
xmin = 0;
xmax = pl->map->mapx - 1;
ymin = 0;
ymax = pl->map->mapy - 1;
}
else
#endif
{
magic_mapping_mark(pl, map_mark, 3);
for(x = 0; x < pl->map->mapx; x++) {
for(y = 0; y < pl->map->mapy; y++) {
if (map_mark[x + pl->map->mapx * y]==1) {
xmin = x < xmin ? x : xmin;
xmax = x > xmax ? x : xmax;
ymin = y < ymin ? y : ymin;
ymax = y > ymax ? y : ymax;
}
}
}
xmin--;
xmin = xmin < 0 ? 0 : xmin;
xmax++;
xmax = xmax > pl->map->mapx - 1 ? pl->map->mapx - 1: xmax;
ymin--;
ymin = ymin < 0 ? 0 : ymin;
ymax++;
ymax = ymax > pl->map->mapy - 1? pl->map->mapy - 1: ymax;
}
pl->contr->viewmap=1;
/* If the width and height of the game window is stored someplace,
* that should be used instead. I just didn't see this information
* anywhere. We could just use the standard width/height
* values, but if the window has been resized larger, things wouldn't
* look right. - Mark Wedel
*/
XGetWindowAttributes(pl->contr->gdisp, pl->contr->win_game, &win_info);
/* If we have color, set for a grey background. From what I have seen,
* grey isn't used much, so with the background grey, it should be easier
* to tell what details magic mapping added - Mark Wedel
* (master@rahul.net)
*/
if (pl->contr->iscolor) {
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->discolor[9].pixel);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
0, 0, win_info.width, win_info.height);
}
else {
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
XClearWindow(pl->contr->gdisp,pl->contr->win_game);
}
res=(WINRIGHT-WINLEFT+1)*24/
(xmax - xmin + 1 > ymax - ymin + 1 ? xmax - xmin + 1 : ymax - ymin + 1);
/* The bitmap used for objects is only 24x24. Too keep things simple,
* so that we don't need to draw it several times, keep the maximum
* resolution 24 pixels. In general, only if magic mapping is mapping
* a very small area will the resolution be greater than 24.
* master@rahul.net
*/
#ifdef ALTERNATE_MM
if (res > 24)
res = 24;
#else
if (!pl->contr->iscolor && res>24) res=24;
#endif
pl->contr->mapres=res;
pl->contr->mapxmin = xmin;
pl->contr->mapymin = ymin;
for (x = xmin; x <= xmax; x++) {
for (y = ymin; y <= ymax; y++) {
if (map_mark[x + pl->map->mapx * y]) {
object *tmp_obj = get_map_ob(pl->map, x, y);
New_Face *f = get_map(pl->map, x, y)->face;
if (f!=blank_face) {
while ((tmp_obj!=NULL) && (tmp_obj->face!=f))
tmp_obj = tmp_obj->above;
/* This shouldn't happen, but might as well check for it */
if (tmp_obj==NULL) {
fprintf(stderr, "Wasn't able to find floor, x=%d, y=%d (magic mapping)\n",x,y);
continue;
}
}
/* This is more complicated than it should be, but..
* If it is blank space, use the background color because the foreground
* color is some odd value that doesn't correspond to what the blank
* space looks like.
* If the object is a wall or blocks the view, and the background is not
* the standard background color, use the background color to draw
* the object. This is really so that the yellow walls (which are
* used on a lot of maps) are displayed properly.
* If the object is a floor, and the foreground color is black, use the
* background. This makes a lot of maps clearer.
*
* NOTE: it is possible for tmp_obj to be NULL, but only when f==G_BLANK.
* Because evaluation of the if statement will end with f==G_BLANK, this
* is ok. But this means that this if statement CAN NOT be re-ordered
* so that IS_FLOOR is evaluated before f==G_BLANK is.
*
* Right now, a lot of objects use a black foreground (most weapon and
* armor, as well as spell books, chairs, tables, ....) If (as) these
* items are colored with a different foreground color, magic mapping will
* become even more useful. However, I suppose there is only so much that
* can be done with 12 colors.
*
* Mark Wedel (master@rahul.net)
*/
if (pl->contr->iscolor) {
#ifdef ALTERNATE_MM
XSetForeground(pl->contr->gdisp, pl->contr->gc_game,
pl->contr->discolor[f->fg].pixel);
XSetBackground(pl->contr->gdisp, pl->contr->gc_game,
pl->contr->discolor[f->bg].pixel);
#else /* ALTERNATE_MM */
if (f->number==blank_face->number ||
(map_mark[x+pl->map->mapx * y]==2 && f->bg!=12) ||
(QUERY_FLAG(tmp_obj, FLAG_IS_FLOOR) && f->fg==0))
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[f->bg].pixel);
else
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[f->fg].pixel);
XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game, 2 + res*(x - xmin),
2 + res*(y - ymin), res, res);
#endif /* ALTERNATE_MM */
}
#ifndef ALTERNATE_MM
else
#endif /* ALTERNATE_MM */
{/* if on black/white system */
/* Above NOTE also applies for this if statement
* Don't do any display for floors on b/w systems
* However, if we aren't using pixmaps, erase the
* space, because a stipple may have overwritten it
*/
if (f->number==blank_face->number ||
(!pl->contr->iscolor && QUERY_FLAG(tmp_obj, FLAG_IS_FLOOR))) {
if (!pl->contr->use_pixmaps) {
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game, 2 + res*(x - xmin),
2 + res*(y - ymin), res, res);
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
}
continue;
}
if (!pl->contr->iscolor && map_mark[x + pl->map->mapx * y]==2)
XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game, 2 + res*(x - xmin),
2 + res*(y - ymin), res, res);
else {
Fontindex use;
#ifdef ALTERNATE_MM
if (!pl->contr->iscolor && itemcolor[f][0]==0)
#else /* ALTERNATE_MM */
if (f->fg==0)
#endif /* ALTERNATE_MM */
use = stipple2_face->number;
else
use = stipple1_face->number;
if (pl->contr->use_pixmaps)
XCopyPlane(pl->contr->gdisp, pl->contr->pixmaps[use],
pl->contr->win_game, pl->contr->gc_game,
0, 0, res,res, 2 + res*(x-xmin), 2+res*(y-ymin),
1);
else {
XChar buf= FontindexToXChar((Fontindex) use);
XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,2+res*(x-xmin),06+res*(y-ymin),&buf,1);
}
}
}
}
else if (!pl->contr->iscolor && !pl->contr->use_pixmaps) {
/* There is no easy way to draw only a portion of a font
* character (at least that I saw.) So, if we used the stipple
* font to draw a character portion, we then need to erase the
* extra portions that were drawn, and this code does that as
* it encounters them.
*/
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XFillRectangle(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game, 2 + res*(x - xmin),
2 + res*(y - ymin), res, res);
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
}
}
}
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gforeground);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,pl->contr->gbackground);
/* If black/white, and uses the font, erase the edges of the
* window. This is to remove any excess pattern that the font
* might leave - master@rahul.net
*/
if (!pl->contr->iscolor && !pl->contr->use_pixmaps) {
XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
(xmax+1-xmin)*res+2, 0, win_info.width - 2 - res*(xmax+1-xmin),
win_info.height);
XFillRectangle(pl->contr->gdisp, pl->contr->win_game, pl->contr->gc_game,
0, 2+res*(ymax+1-ymin), win_info.width, win_info.height-2 -
res*(ymax+1-ymin));
}
free(map_mark);
}
/* Note: For improved magic mapping display, the space that blocks
* the view is now marked with value 2. Any dependencies of map_mark
* being nonzero have been changed to check for 1. Also, since
* map_mark is a char value, putting 2 in should cause no problems.
* Mark Wedel (master@rahul.net)
*/
void magic_mapping_mark(object *pl, char *map_mark, int strength)
{
int x, y;
int xmin = pl->x - strength + 1 < 0 ? 0 : pl->x - strength + 1;
int xmax = pl->x + strength - 1 > pl->map->mapx - 1 ?
pl->map->mapx - 1 : pl->x + strength - 1;
int ymin = pl->y - strength + 1 < 0 ? 0 : pl->y - strength + 1;
int ymax = pl->y + strength - 1 > pl->map->mapy - 1 ?
pl->map->mapy - 1 : pl->y + strength - 1;
for (x = xmin; x <= xmax; x++) {
for (y = ymin; y <= ymax; y++) {
if (wall(pl->map, x, y) || blocks_view(pl->map, x, y))
map_mark[x + pl->map->mapx * y] = 2;
else {
map_mark[x + pl->map->mapx * y] = 1;
magic_mapping_mark_recursive(pl, map_mark, x, y);
}
}
}
}
void magic_mapping_mark_recursive(object *pl, char *map_mark, int px, int py)
{
int x, y, dx, dy;
for (dx = -1; dx <= 1; dx++) {
for (dy = -1; dy <= 1; dy++) {
x = px + dx;
y = py + dy;
if (x >= 0 && x < pl->map->mapx && y >= 0 && y < pl->map->mapy
&& (map_mark[x + pl->map->mapx * y] ==0) ) {
if (blocks_view(pl->map, x, y))
map_mark[x + pl->map->mapx * y] = 2;
else {
if (wall(pl->map, x, y))
map_mark[x + pl->map->mapx * y] = 2;
else
map_mark[x + pl->map->mapx * y] = 1;
magic_mapping_mark_recursive(pl, map_mark, x, y);
}
}
}
}
}
#endif /* CD_DRAW_MAP */
void draw(object *pl) {
int i,j,last_f= -1,last_b= -1,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
XChar buf;
New_Face *f;
if(pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY)
return;
if(pl->contr->viewmap) {
draw_dots(pl);
return;
}
if(pl->contr->do_los) {
update_los(pl);
#ifdef USE_LIGHTING
pl->map->do_los = 0;
#endif
pl->contr->do_los = 0;
}
#ifdef Xpm_Pix
if (pl->contr->color_pixmaps) {
draw_color_pix(pl);
return;
}
#endif
if(pl->contr->use_pixmaps) {
draw_pix(pl);
return;
}
if(!pl->contr->iscolor) {
draw_bw(pl); /* This function optimizes better */
return;
}
/* The following looks like it only applies to bw systems using
* the font.
*/
buf= FontindexToXChar((Fontindex) 0);
for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
ay=j-pl->y-WINUPPER;
for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
ax=i-pl->x-WINLEFT;
f = (out_of_map(pl->map,i,j)||
pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])?
blocked_face : get_map(pl->map,i,j)->face;
if(f!= pl->contr->drawn[ax][ay]) {
buf=FontindexToXChar(f->number);
pl->contr->drawn[ax][ay]=f;
if(pl->contr->discolor[f->fg].pixel!=last_f)
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
(last_f=pl->contr->discolor[f->fg].pixel));
if(pl->contr->discolor[f->bg].pixel!=last_b)
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
(last_b=pl->contr->discolor[f->bg].pixel));
XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,2+24*ax,ay*24+26,&buf,1);
}
}
}
if(pl->invisible & (pl->invisible<50 ? 4 : 1)) {
pl->contr->drawn[5][5]=pl->face;
buf=FontindexToXChar(pl->face->number);
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[pl->face->fg].pixel);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[pl->face->bg].pixel);
XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,122,146,&buf,1);
}
}
void draw_pix(object *pl) {
int i,j,last_f= -1,last_b= -1,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
New_Face *f;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_pix");
return;
}
if(pl->contr->viewmap) {
draw_dots(pl);
return;
}
for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
ay=j-pl->y-WINUPPER;
for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
ax=i-pl->x-WINLEFT;
f=(out_of_map(pl->map,i,j)||
pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])?
blocked_face : get_map(pl->map,i,j)->face;
if(f!=pl->contr->drawn[ax][ay]) {
pl->contr->drawn[ax][ay]=f;
if(pl->contr->iscolor) {
if(pl->contr->discolor[f->fg].pixel!=last_f)
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
(last_f=pl->contr->discolor[f->fg].pixel));
if(pl->contr->discolor[f->bg].pixel!=last_b)
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
(last_b=pl->contr->discolor[f->bg].pixel));
}
XCopyPlane(pl->contr->gdisp,pl->contr->pixmaps[f->number],
pl->contr->win_game,pl->contr->gc_game,
0,0,24,24,2+24*ax,2+24*ay,1);
}
}
}
if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
pl->contr->drawn[5][5] = pl->face;
if(pl->contr->iscolor) {
XSetForeground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[pl->face->fg].pixel);
XSetBackground(pl->contr->gdisp,pl->contr->gc_game,
pl->contr->discolor[pl->face->bg].pixel);
}
XCopyPlane(pl->contr->gdisp,pl->contr->pixmaps[pl->face->number],
pl->contr->win_game,pl->contr->gc_game,0,0,24,24,122,122,1);
}
}
void draw_bw(object *pl) {
int i,j,left,right,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
XChar buff[20];
New_Face *tmp;
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_foo(pl->contr->eric_server,"draw_bw");
return;
}
for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
left= -1,right=0,ay=j-pl->y-WINUPPER;
for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
ax=i-pl->x-WINLEFT;
tmp = (out_of_map(pl->map,i,j)||
pl->contr->blocked_los[i+5-pl->x][j+5-pl->y]) ?
blocked_face : get_map(pl->map,i,j)->face;
if(tmp!=pl->contr->drawn[ax][ay]) {
pl->contr->drawn[ax][ay]=tmp;
if(left== (-1)) left=ax;
right=ax;
}
buff[ax] = FontindexToXChar(tmp->number);
}
if(left!=-1)
XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,2+24*left,ay*24+26,buff+left,
right-left+1);
}
if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
buff[0]=FontindexToXChar(pl->face->number);
pl->contr->drawn[5][5] = pl->face;
XDRAWIMAGESTRING(pl->contr->gdisp,pl->contr->win_game,
pl->contr->gc_game,122,122,buff,1);
}
}
#ifdef Xpm_Pix
void draw_client_map(object *pl)
{
int i,j,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
New_Face *face,*floor;
#ifdef DOUBLE_FLOOR
New_Face *floor2;
#endif
if (pl->type == PLAYER && pl->contr->eric_server > 0) {
esrv_map_new(pl->contr->eric_server); /* implicitly clears all cells */
if(pl->invisible & (pl->invisible < 50 ? 4 : 1)) {
esrv_map_setbelow(pl->contr->eric_server,5,5,pl->face->number);
}
for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
ay=j-pl->y-WINUPPER;
for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
ax=i-pl->x-WINLEFT;
if (!(out_of_map(pl->map,i,j) ||
pl->contr->blocked_los[i+5-pl->x][j+5-pl->y])) {
face = get_map(pl->map, i, j)->face;
floor = get_map_floor(pl->map, i,j)->face;
#ifdef DOUBLE_FLOOR
floor2 = get_map_floor2(pl->map, i,j)->face;
#endif
if (face == blank_face &&
#ifdef DOUBLE_FLOOR
floor2 == blank_face &&
#endif
floor == blank_face) {
esrv_map_setbelow(pl->contr->eric_server,ax,ay,blank_face->number);
} else {
if (face != blank_face)
esrv_map_setbelow(pl->contr->eric_server,ax,ay,face->number);
#ifdef DOUBLE_FLOOR
if (floor2 != blank_face)
esrv_map_setbelow(pl->contr->eric_server,ax,ay,floor2->number);
#endif
if (floor != blank_face)
esrv_map_setbelow(pl->contr->eric_server,ax,ay,floor->number);
}
}
}
}
esrv_map_doneredraw(pl->contr->eric_server);
return;
}
}
/* draw_color_pix is orignally from draw_pix. I separated them for reasons
* of speed. The main differences are these: Color pixmaps do not need
* foreground and background set (it does nothing), but does need
* to set the bitmask for objects.
*
* Because of shape masks, this function has become a little more complicated,
* and probably slower. The other option is to keep it like draw_pix and
* the other draw functions, and only draw the top object. However, I think
* one of the advantages of the color pixmaps is that you do have a shape
* mask, and it would be a shame not to use it.
*
* A re-draw is done only if the top object on a square is changed.
*`As far as I know, floors can not really change unless someone moves
* on top of them, so this should work fine.
* An exception to this is the player, as he can move in the same direction.
* His face remains the same, but the floor underneath him changes.
*
* One thought to perhaps make the function quicker and reduce flicker
* would be to draw all the floors on the first pass, then come back and
* draw the objects. This should be quicker, because the floors should
* not need any of the clipmasks.
* The best way to reduce flicker would probably be to draw both the
* floor and object into a new pixmap, and then draw that pixmap onto
* the screen. It might even be a little quicker, because the ClipOrigin
* should only need to be set once.
*/
/* New version of draw_color_pix. This should hopefully run faster and
* with less jittering than the old routine. It does cost a little more
* memory (2 gc's and a 24x24 pixmap added to the player structure.)
* The gc's have some values pre-set so that this routine does not need to
* set them for each pixmap drawn.
*/
void draw_color_pix(object *pl) {
int i,j,ax,ay; /* ax and ay goes from 0 to max-size of arrays */
New_Face *face,*floor;
#ifdef DOUBLE_FLOOR
New_Face *floor2;
#endif
static Pixmap obj_mask = 0;
if (pl->contr->eric_server>0) {
draw_client_map(pl);
return;
}
for(j=pl->y+WINUPPER;j<=pl->y+WINLOWER;j++) {
ay=j-pl->y-WINUPPER;
for(i=pl->x+WINLEFT;i<=pl->x+WINRIGHT;i++) {
ax=i-pl->x-WINLEFT;
if (out_of_map(pl->map,i,j) ||
pl->contr->blocked_los[i+5-pl->x][j+5-pl->y]) {
if (pl->contr->drawn[ax][ay]!=blocked_face) {
/* A XClearArea is probably faster than copying the pixmap.
* (it also works better)
* Also, this way we do not need to worry about any masking
* values.
* What might be better is to detect which cooridnate (i or j)
* is out of bounds of the map. Since all maps are square,
* then one XClearArea could be used to clear the entire
* row or column, and then break out. This would
* skip several checks.
* Mark Wedel (master@rahul.net)
*/
XClearArea(pl->contr->gdisp, pl->contr->win_game,
2+24*ax, 2+24*ay, 24, 24, False);
pl->contr->drawn[ax][ay] = blocked_face;
}
}
else {
face = get_map(pl->map, i, j)->face;
floor = get_map_floor(pl->map, i,j)->face;
#ifdef DOUBLE_FLOOR
floor2 = get_map_floor2(pl->map, i,j)->face;
if (face!=pl->contr->drawn[ax][ay] ||
floor!=pl->contr->floor[ax][ay] ||
floor2!=pl->contr->floor2[ax][ay]) {
#else
if (face!=pl->contr->drawn[ax][ay] ||
floor!=pl->contr->floor[ax][ay]) {
#endif
XCopyArea(pl->contr->gdisp, pl->contr->pixmaps[floor->number],
pl->contr->xpm_pixmap, pl->contr->gc_xpm_floor,
0, 0, 24, 24, 0, 0);
#ifdef DOUBLE_FLOOR
/* If there is a second FLOOR_TYPE item on top of the
* first, draw it with the right clipmask. This looks
* good, but may be expensive as 3 pixmaps are drawn
* instead of 2.
* Gregor Schmid (schmid@fb3-s7.math.tu-berlin.de)
*/
if (floor2 != blank_face) {
XSetClipMask(pl->contr->gdisp,
pl->contr->gc_xpm_floor,
pl->contr->masks[floor2->number]);
XCopyArea(pl->contr->gdisp,
pl->contr->pixmaps[floor2->number],
pl->contr->xpm_pixmap,pl->contr->gc_xpm_floor,
0,0,24,24,0, 0);
XSetClipMask(pl->contr->gdisp,
pl->contr->gc_xpm_floor,None);
}
#endif
if (obj_mask != pl->contr->masks[face->number]) {
XSetClipMask(pl->contr->gdisp, pl->contr->gc_xpm_object,
pl->contr->masks[face->number]);
obj_mask = pl->contr->masks[face->number];
}
XCopyArea(pl->contr->gdisp,pl->contr->pixmaps[face->number],
pl->contr->xpm_pixmap,pl->contr->gc_xpm_object,
0,0,24,24,0, 0);
XCopyArea(pl->contr->gdisp,pl->contr->xpm_pixmap,
pl->contr->win_game,pl->contr->gc_game,
0,0,24,24,2+24*ax,2+24*ay);
pl->contr->floor[ax][ay] = floor;
pl->contr->drawn[ax][ay]= face;
#ifdef DOUBLE_FLOOR
pl->contr->floor2[ax][ay] = floor2;
#endif
}
}
}
}
if(pl->invisible && (pl->invisible < 50 ? 4 : 1)) {
pl->contr->drawn[5][5] = pl->face;
XCopyArea(pl->contr->gdisp,pl->contr->pixmaps[pl->face->number],
pl->contr->win_game,pl->contr->gc_game,0,0,24,24,122,122);
}
}
#endif